﻿/**
* CRL
*/
using CRL.DBAccess;
using CRL.DBAdapter;
using CRL.LambdaQuery;
using CRL.Sharding;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace CRL
{
    public interface IDbConfigRegister
    {
        /// <summary>
        /// 注册数据访问实现
        /// 按优先顺序添加,不成立则返回null
        /// </summary>
        /// <param name="func"></param>
        void RegisterDBAccessBuild(Func<DBLocation, DBAccessBuild> func);
        /// <summary>
        /// 注册定位
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        void RegisterLocation<T>(Func<Attribute.TableInnerAttribute, T, Location> func);

        /// <summary>
        /// 注册自定义扩展方法(仅关系型数据库)
        /// </summary>
        /// <param name="dBType"></param>
        /// <param name="methodName"></param>
        /// <param name="handler"></param>
        void AddCustomExtendMethod(DBType dBType, string methodName, MethodHandler handler);

    }

    //core Singleton注入下，只读的问题
    internal class DBConfigRegisterContainer
    {
        internal static Dictionary<DBType, Func<DBAccessBuild, DBHelper>> DBHelperRegister = new Dictionary<DBType, Func<DBAccessBuild, DBHelper>>();

        internal static Dictionary<DBType, Func<DbContextInner, DBAdapterBase>> DBAdapterBaseRegister = new Dictionary<DBType, Func<DbContextInner, DBAdapterBase>>();

        internal static Dictionary<DBType, Func<DbContextInner, AbsDBExtend>> AbsDBExtendRegister = new Dictionary<DBType, Func<DbContextInner, AbsDBExtend>>();

        internal static List<Func<DBLocation, DBAccessBuild>> DbAccessCreaterRegister = new List<Func<DBLocation, DBAccessBuild>>();

        internal static Dictionary<DBType, Type> LambdaQueryTypeRegister = new Dictionary<DBType, Type>();

        internal static Dictionary<Type, object> LocationRegister = new Dictionary<Type, object>();

        internal static Dictionary<string, DBType> ConnectionTypeMapping = new Dictionary<string, DBType>();
    }
    public class DBConfigRegister : IDbConfigRegister
    {
        static DBConfigRegister instance;
        static DBConfigRegister()
        {
            instance = new DBConfigRegister();

            #region 注册默认数据库类型
            var configBuilder = instance;
            configBuilder.RegisterDBType(DBType.MSSQL, (dBAccessBuild) =>
            {
                return new SqlHelper(dBAccessBuild);
            }, (context) =>
            {
                return new MSSQLDBAdapter(context);
            });
            //configBuilder.RegisterDBType(DBType.MSSQL2000, (dBAccessBuild) =>
            //{
            //    return new Sql2000Helper(dBAccessBuild);
            //}, (context) =>
            //{
            //    return new MSSQL2000DBAdapter(context);
            //});
            configBuilder.RegisterDBExtend<DBExtend.RelationDB.DBExtend>(DBType.MSSQL, (context) =>
            {
                return new DBExtend.RelationDB.DBExtend(context);
            });
            configBuilder.RegisterLambdaQueryType(DBType.MSSQL, typeof(RelationLambdaQuery<>));
            configBuilder.RegisterConnectionTypeMapping(nameof(System.Data.SqlClient.SqlConnection), DBType.MSSQL);
            #endregion

        }
        public static IDbConfigRegister GetInstance()
        {
            return instance;
        }

        /// <summary>
        /// 注册数据访问实现，可以覆盖
        /// </summary>
        /// <param name="dBType"></param>
        /// <param name="funcDb"></param>
        /// <param name="funcDBAdapter"></param>
        /// <returns></returns>
        public DBConfigRegister RegisterDBType(DBType dBType, Func<DBAccessBuild, DBHelper> funcDb, Func<DbContextInner, DBAdapter.DBAdapterBase> funcDBAdapter)
        {
            if (funcDb != null)
            {
                DBConfigRegisterContainer.DBHelperRegister.Remove(dBType);
                DBConfigRegisterContainer.DBHelperRegister.Add(dBType, funcDb);
            }
            if (funcDBAdapter != null)
            {
                DBConfigRegisterContainer.DBAdapterBaseRegister.Remove(dBType);
                DBConfigRegisterContainer.DBAdapterBaseRegister.Add(dBType, funcDBAdapter);
            }
            return this;
        }
        /// <summary>
        /// 注册ConnectionTypeName和DBType映射
        /// </summary>
        /// <param name="name"></param>
        /// <param name="dBType"></param>
        /// <returns></returns>
        public DBConfigRegister RegisterConnectionTypeMapping(string name, DBType dBType)
        {
            DBConfigRegisterContainer.ConnectionTypeMapping[name] = dBType;
            return this;
        }
        internal DBType GetConnectionTypeMapping(string name)
        {
            var a = DBConfigRegisterContainer.ConnectionTypeMapping.TryGetValue(name, out var dBType);
            if(!a)
            {
                throw new Exception($"未找到 {name} 注册");
            }
            return dBType;
        }

        public DBConfigRegister RegisterDBExtend<T1>(DBType dBType, Func<DbContextInner, AbsDBExtend> func) where T1 : AbsDBExtend
        {
            if (!DBConfigRegisterContainer.AbsDBExtendRegister.ContainsKey(dBType))
            {
                DBConfigRegisterContainer.AbsDBExtendRegister.Add(dBType, func);
            }
            return this;
        }

        public DBConfigRegister RegisterLambdaQueryType(DBType dBType, Type type)
        {
            if (!DBConfigRegisterContainer.LambdaQueryTypeRegister.ContainsKey(dBType))
            {
                DBConfigRegisterContainer.LambdaQueryTypeRegister.Add(dBType, type);
            }
            return this;
        }
        /// <summary>
        /// 注册数据访问实现
        /// 按优先顺序添加,不成立则返回null
        /// </summary>
        /// <param name="func"></param>
        public void RegisterDBAccessBuild(Func<DBLocation, DBAccessBuild> func)
        {
            DBConfigRegisterContainer.DbAccessCreaterRegister.Add(func);
        }
        public void RegisterLocation<T>(Func<Attribute.TableInnerAttribute, T, Location> func)
        {
            DBConfigRegisterContainer.LocationRegister.Add(typeof(T), func);
        }

        internal static Func<Attribute.TableInnerAttribute, T, Location> GetLocation<T>()
        {
            var a = DBConfigRegisterContainer.LocationRegister.TryGetValue(typeof(T), out object value);
            if (a)
            {
                return value as Func<Attribute.TableInnerAttribute, T, Location>;
            }
            return null;
        }

        public static DBHelper GetDBHelper(DBLocation location)
        {
            var dBAccessBuild = GetDBAccessBuild(location);
            return GetDBHelper(dBAccessBuild);
        }
        public static DBHelper GetDBHelper(DBAccessBuild dBAccessBuild)
        {
            var exists = DBConfigRegisterContainer.DBHelperRegister.TryGetValue(dBAccessBuild._DBType, out var func);
            if (!exists)
            {
                throw new Exception("未配置对应的数据库类型:" + dBAccessBuild._DBType);
            }
            return func(dBAccessBuild);
        }
        internal static DBAdapterBase GetDBAdapterBase(DbContextInner dbContext)
        {
            var exists = DBConfigRegisterContainer.DBAdapterBaseRegister.TryGetValue(dbContext.DBHelper.CurrentDBType, out var func);
            if (!exists)
            {
                throw new Exception("找不到对应的DBAdapte" + dbContext.DBHelper.CurrentDBType);
            }
            return func(dbContext);
        }

        static DBAccessBuild GetDBAccessBuild(DBLocation location)
        {
            foreach (var m in DBConfigRegisterContainer.DbAccessCreaterRegister)
            {
                var act = m(location);
                if (act != null)
                {
                    return act;
                }
            }
            throw new Exception($"未找到对应的数据访问实现");
        }
        internal static AbsDBExtend CreateDBExtend(DbContextInner _dbContext)
        {
            var dbType = _dbContext.DBHelper.CurrentDBType;
            if (_dbContext.DataBaseArchitecture == DataBaseArchitecture.Relation)
            {
                return new DBExtend.RelationDB.DBExtend(_dbContext);
            }
            var a = DBConfigRegisterContainer.AbsDBExtendRegister.TryGetValue(dbType, out Func<DbContextInner, AbsDBExtend> func);
            if (!a)
            {
                throw new Exception($"未找到AbsDBExtend {dbType}");
            }
            return func(_dbContext);
        }
        internal static Type GetLambdaQueryType(DBType dBType)
        {
            var a = DBConfigRegisterContainer.LambdaQueryTypeRegister.TryGetValue(dBType, out Type type);
            if (!a)
            {
                throw new Exception($"未找到对应的LambdaQueryType{dBType}");
            }
            return type;
        }
        public void AddCustomExtendMethod(DBType dBType, string methodName, MethodHandler handler)
        {
            MethodAnalyze.AddCustomExtendMethod(dBType, methodName, handler);
        }
    }

}
